/*
 * Copyright (c) 2023-2024 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.screw.process;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.elsfs.cloud.common.util.lang.StringUtils;
import org.elsfs.cloud.screw.Configuration;
import org.elsfs.cloud.screw.constant.ScrewConstants;
import org.elsfs.cloud.screw.metadata.Column;
import org.elsfs.cloud.screw.metadata.Database;
import org.elsfs.cloud.screw.metadata.PrimaryKey;
import org.elsfs.cloud.screw.metadata.Table;
import org.elsfs.cloud.screw.metadata.model.ColumnModel;
import org.elsfs.cloud.screw.metadata.model.DataModel;
import org.elsfs.cloud.screw.metadata.model.TableModel;
import org.elsfs.cloud.screw.query.DatabaseQuery;
import org.elsfs.cloud.screw.query.DatabaseQueryFactory;

/**
 * 数据模型处理
 *
 * @author zeng
 */
@Slf4j
public class DataModelProcess extends AbstractProcess {

  /**
   * 构造方法
   *
   * @param configuration {@link Configuration}
   */
  public DataModelProcess(Configuration configuration) {
    super(configuration);
  }

  private static final Map<String, DatabaseQuery> databaseQueryMap = new HashMap<>();

  /**
   * 处理
   *
   * @return {@link DataModel}
   */
  @Override
  public DataModel process(String dsName) {
    // 获取query对象
    DatabaseQuery databaseQuery = databaseQueryMap.get(dsName);

    if (databaseQuery == null) {
      databaseQuery = new DatabaseQueryFactory(config.getDataSource()).newInstance();
      databaseQueryMap.put(dsName, databaseQuery);
    }
    DataModel model = new DataModel();
    // Title
    model.setTitle(config.getTitle());
    // org
    model.setOrganization(config.getOrganization());
    // org url
    model.setOrganizationUrl(config.getOrganizationUrl());
    // version
    model.setVersion(config.getVersion());
    // description
    model.setDescription(config.getDescription());

    /*查询操作开始*/
    long start = System.currentTimeMillis();
    // 获取数据库
    Database database = databaseQuery.getDataBase();
    LOGGER.debug("query the database time consuming:{}ms", (System.currentTimeMillis() - start));
    model.setDatabase(database.getDatabase());
    start = System.currentTimeMillis();
    LOGGER.debug("query the table time consuming:{}ms", (System.currentTimeMillis() - start));
    // 获取全部列
    start = System.currentTimeMillis();
    List<? extends Column> columns = databaseQuery.getTableColumns();
    LOGGER.debug("query the column time consuming:{}ms", (System.currentTimeMillis() - start));
    // 获取主键
    start = System.currentTimeMillis();
    List<? extends PrimaryKey> primaryKeys = databaseQuery.getPrimaryKeys();
    LOGGER.debug("query the primary key time consuming:{}ms", (System.currentTimeMillis() - start));
    /*查询操作结束*/

    /*处理数据开始*/
    start = System.currentTimeMillis();
    List<TableModel> tableModels = new ArrayList<>();
    // 获取全部表
    List<? extends Table> tables = databaseQuery.getTables();
    tablesCaching.put(database.getDatabase(), tables);
    for (Table table : tables) {
      // 处理列，表名为key，列名为值
      columnsCaching.put(
          table.getTableName(),
          columns.stream()
              .filter(i -> i.getTableName().equals(table.getTableName()))
              .collect(Collectors.toList()));
      // 处理主键，表名为key，主键为值
      primaryKeysCaching.put(
          table.getTableName(),
          primaryKeys.stream()
              .filter(i -> i.getTableName().equals(table.getTableName()))
              .collect(Collectors.toList()));
    }
    for (Table table : tables) {
      /*封装数据开始*/
      TableModel tableModel = new TableModel();
      // 表名称
      tableModel.setTableName(table.getTableName());
      // 说明
      tableModel.setRemarks(table.getRemarks());
      // 添加表
      tableModels.add(tableModel);
      // 处理列
      List<ColumnModel> columnModels = new ArrayList<>();
      // 获取主键
      List<String> key =
          primaryKeysCaching.get(table.getTableName()).stream()
              .map(PrimaryKey::getColumnName)
              .collect(Collectors.toList());
      for (Column column : columnsCaching.get(table.getTableName())) {
        packageColumn(columnModels, key, column);
      }
      // 放入列
      tableModel.setColumns(columnModels);
    }
    // 设置表
    model.setTables(filterTables(tableModels));
    // 优化数据
    optimizeData(model);
    /*封装数据结束*/
    LOGGER.debug(
        "encapsulation processing data time consuming:{}ms", (System.currentTimeMillis() - start));
    return model;
  }

  /**
   * packageColumn
   *
   * @param columnModels {@link List}
   * @param keyList {@link List}
   * @param column {@link Column}
   */
  private void packageColumn(List<ColumnModel> columnModels, List<String> keyList, Column column) {
    ColumnModel columnModel = new ColumnModel();
    // 表中的列的索引（从 1 开始）
    columnModel.setOrdinalPosition(column.getOrdinalPosition());
    // 列名称
    columnModel.setColumnName(column.getColumnName());
    // 类型
    columnModel.setColumnType(column.getColumnType());
    // 字段名称
    columnModel.setTypeName(column.getTypeName());
    // 长度
    columnModel.setColumnLength(column.getColumnLength());
    columnModel.setColumnLength(column.getColumnLength());
    // size
    columnModel.setColumnSize(column.getColumnSize());
    // 小数位
    columnModel.setDecimalDigits(
        StringUtils.defaultString(column.getDecimalDigits(), ScrewConstants.ZERO_DECIMAL_DIGITS));
    // 可为空
    columnModel.setNullable(
        ScrewConstants.ZERO.equals(column.getNullable()) ? ScrewConstants.N : ScrewConstants.Y);
    // 是否主键
    columnModel.setPrimaryKey(
        keyList.contains(column.getColumnName()) ? ScrewConstants.Y : ScrewConstants.N);
    // 默认值
    columnModel.setColumnDef(column.getColumnDef());
    // 说明
    columnModel.setRemarks(column.getRemarks());
    // 放入集合
    columnModels.add(columnModel);
  }
}
